In certain cases getBoundingClientRect() produces wrong results and is hence an unreliable function. In Chrome at least. Example:
var greenRectangle = document.getElementById("target")
var rect = greenRectangle.getBoundingClientRect()
var visualized = document.createElement("div")
visualized.style.position = "absolute"
visualized.style.border = "1px solid red"
visualized.style.top = rect.top+"px"
visualized.style.left = rect.left+"px"
visualized.style.width = rect.width+"px"
visualized.style.height = rect.height+"px"
visualized.style.background = "#ff00002e"
document.body.appendChild(visualized)
<html>
<body>
<div style="transform: translate(10px, 42px);">
<div style="width: 100px;height: 300px;background: black;">
<div style="transform: translate(140px, -10px);width: 400px;height: 300px;">
<div>
<div id="target" style="transform: translate(89px, 28px) rotate(2rad); width: 200px; height: 100px; background: green;"></div>
</div>
</div>
</div>
</div>
</body>
</html>
If the green rectangle is rotated then getBoundingClientRect() on it returns a wrong bounding rectangle - here shown in red. I have tested this in Firefox and there are no problems there. It seems to have something to do with the empty div wrapper around the green rectangle. Without it getBoundingClientRect() works correctly. It looks like a Chrome bug to me. Is there a way to work around that?
EDIT: This seems to have been fixed by now, at least for the example case in this snippet. I'm not sure if there are other cases where getBoundingClientRect() returns wrong values.
SVG LINE BOUNDING CALCULATION ERROR - STILL CHROME
UPDATE: More information on this bug can be found here: SVG getBoundingClientRect() + "transform: rotate()" is bugged in Chrome in a very specific way
I've spent some time trying to hunt down why I wasn't getting the correct ClientBounds which led me to this question. You stated "I'm not sure if there are other cases where getBoundingClientRect() returns wrong values.". Well, it turns out there are more cases. This time in regard to SVGs but it is quite peculiar. I thought I'd leave this here for anyone else that comes across your post with a similar problem.
getBoundingClientRect() works fine on all SVG elements except in the circumstance when an element is rotated.
Below I have drawn 2 lines, the one on the left is diagonal, the right line starts vertical as represented by the black line. The green box is a visual representation of the getBoundingClientRect(). I then apply the same transform rotate to both lines at the same time and then update the bounding box visual.
As you can see from the following, the left bounding box doesn't represent the actual bounds, however, the right one does.
let l1 = document.getElementById("line1"),
l2 = document.getElementById("line2"),
vis1 = document.createElement("div"),
vis2 = document.createElement("div"),
r = 0;
let setUpVis = (element) => {
document.body.appendChild(element)
element.style.position = "absolute"
element.style.border = "1px solid green"
element.style.background = `#0FF0002e`
}
let updateBounds = (element, displayElement) => {
element.setAttribute("transform", `rotate(${r} 80 80)`);
let rect = element.getBoundingClientRect()
displayElement.style.top = rect.y+"px"
displayElement.style.left = rect.x+"px"
displayElement.style.width = rect.width+"px"
displayElement.style.height = rect.height+"px"
}
setUpVis(vis1)
setUpVis(vis2)
setInterval(() => {
updateBounds(l1, vis1);
updateBounds(l2, vis2);
r++;
if(r===360) r=0;
}, 10)
.container {
width:170px;
height:170px;
display:inline-block;
}
<svg xmlns="http://www.w3.org/2000/svg" class="container">
<line x1="40" y1="40" x2="120" y2="120" stroke="black" stroke-width="2"></line>
<line x1="40" y1="40" x2="120" y2="120" id="line1" stroke="red" stroke-width="2"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" class="container">
<line x1="80" y1="30" x2="80" y2="130" stroke="black" stroke-width="2"></line>
<line x1="80" y1="30" x2="80" y2="130" id="line2" stroke="red" stroke-width="2"></line>
</svg>